﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using Microsoft.Office.PowerPoint.STAMP.Core;

namespace Microsoft.Office.PowerPoint.STAMP.Command
{
    public class CaptionExporter
    {
        private readonly IEnumerable<CaptionItem> _captionItems;

        /// <summary>
        /// Initializes a new instance of the <see cref="CaptionExporter"/> class.
        /// </summary>
        /// <param name="captionItems">The caption items.</param>
        public CaptionExporter(IEnumerable<CaptionItem> captionItems)
        {
            _captionItems = captionItems;
        }

        /// <summary>
        /// Exports to TTML.
        /// </summary>
        /// <returns></returns>
        public string ExportToTTML()
        {
            StringBuilder stringBuilder = new StringBuilder();
            using (StringWriter textWriter = new StringWriter(stringBuilder))
            using (XmlTextWriter writer = new XmlTextWriter(textWriter))
            {
                Dictionary<CaptionStyle, string> captionStyles = new Dictionary<CaptionStyle, string>();
                Dictionary<CaptionItem, string> captionToCaptionStylesMap = new Dictionary<CaptionItem, string>();

                PopulateCaptionStyleMaps(captionStyles, captionToCaptionStylesMap, _captionItems);

                WriteCaptionHeader(writer);
                WriteCaptionStyles(writer, captionStyles);
                WriteBody(writer, captionToCaptionStylesMap);
            }
            return stringBuilder.ToString();
        }

        private void WriteBody(XmlTextWriter writer, Dictionary<CaptionItem, string> captionToCaptionStylesMap)
        {
            writer.WriteStartElement("body");
            writer.WriteStartElement("div");
            writer.WriteAttributeString("xml:lang", "en");
            foreach (CaptionItem captionItem in _captionItems)
            {
                WriteCaption(writer, captionItem, captionToCaptionStylesMap);
            }
        }

        private static void WriteCaptionStyles(XmlTextWriter writer, Dictionary<CaptionStyle, string> captionStyles)
        {
            if (captionStyles.Count > 0)
            {
                writer.WriteStartElement("head");
                writer.WriteStartElement("styling");
                writer.WriteAttributeString("xmlns:tts", "http://www.w3.org/ns/ttml#styling");
                foreach (KeyValuePair<CaptionStyle, string> captionStyle in captionStyles)
                {
                    WriteCaptionStyle(writer, captionStyle.Key, captionStyle.Value);
                }
                writer.WriteEndElement();
                writer.WriteEndElement();
            }
        }

        private static void WriteCaptionStyle(XmlTextWriter writer, CaptionStyle captionStyle, string captionStyleId)
        {
            writer.WriteStartElement("style");
            writer.WriteAttributeString("xml:id", captionStyleId);
            writer.WriteAttributeString("tts:color", ColorTranslator.ToHtml(captionStyle.FontColor));
            writer.WriteAttributeString("tts:backgroundColor", ColorTranslator.ToHtml(captionStyle.BackgroundColor));
            if (captionStyle.FontFamily != null)
            {
                writer.WriteAttributeString("tts:fontFamily", captionStyle.FontFamily.Name);
            }
            if (captionStyle.FontSize != null)
            {
                writer.WriteAttributeString("tts:fontSize", captionStyle.FontSize.ToString());
            }
            writer.WriteAttributeString("tts:textAlign", captionStyle.TextAlignStyleProperty.ToString());
            if (captionStyle.FontStyle.HasFlag(FontStyle.Bold))
                writer.WriteAttributeString("tts:fontWeight", "bold");
            if (captionStyle.FontStyle.HasFlag(FontStyle.Italic))
                writer.WriteAttributeString("tts:fontStyle", "italic");
            if (captionStyle.FontStyle.HasFlag(FontStyle.Underline))
                writer.WriteAttributeString("tts:textDecoration", "underline");
            writer.WriteEndElement();
        }

        private static void PopulateCaptionStyleMaps(Dictionary<CaptionStyle, string> captionStyleByStyleKey, Dictionary<CaptionItem, string> captionItemByCaptionStyleKey, IEnumerable<CaptionItem>  captionItems)
        {
            int styleCounter = 1;
            foreach (CaptionItem captionItem in captionItems)
            {
                string key;
                if (captionItem.CaptionStyle == null)
                {
                    key = string.Empty;
                }
                else if (captionStyleByStyleKey.ContainsKey(captionItem.CaptionStyle))
                {
                    key = captionStyleByStyleKey[captionItem.CaptionStyle];
                }
                else
                {
                    key = "Style" + styleCounter++;
                    captionStyleByStyleKey.Add(captionItem.CaptionStyle, key);
                }
                captionItemByCaptionStyleKey.Add(captionItem, key);
            }    
        }

        private static void WriteCaptionHeader(XmlTextWriter writer)
        {
            writer.WriteProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");
            writer.WriteStartElement("tt");
            writer.WriteAttributeString("xmlns", "http://www.w3.org/ns/ttml");
            writer.WriteAttributeString("xmlns:tts", "http://www.w3.org/ns/ttml#styling");
            writer.WriteAttributeString("xml:lang", "en");
        }

        private static void WriteCaption(XmlTextWriter writer, CaptionItem captionItem, Dictionary<CaptionItem, string> captionToCaptionStylesMap)
        {
            writer.WriteStartElement("p");
            string styleId = captionToCaptionStylesMap[captionItem];
            if (!String.IsNullOrEmpty(styleId))
                writer.WriteAttributeString("style", styleId);
            writer.WriteAttributeString("begin", captionItem.BookMarkEntryPosition.ToTimeSpanString());
            writer.WriteAttributeString("end", captionItem.BookMarkExitPosition.ToTimeSpanString());
            writer.WriteString(captionItem.Text);
            writer.WriteEndElement();
        }
    }
}